<?php 
/**
 * @author MarcusM. works for huike. QQ:2453302174
 */
class WxInterface extends CApplicationComponent
{
	use BasicTrait;
	
	protected static $_NOW = 0;
	
	protected $_wxplatform = null;
	
	protected $_curl;
	protected function _cInit()
	{
		$this->_curl = curl_init();
		curl_setopt($this->_curl, CURLOPT_HTTPHEADER, array(
			"content-type: application/x-www-form-urlencoded; charset=UTF-8"
		));
		curl_setopt($this->_curl, CURLOPT_SSL_VERIFYHOST, 0);
		curl_setopt($this->_curl, CURLOPT_SSL_VERIFYPEER, 0);
		curl_setopt($this->_curl, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($this->_curl, CURLOPT_CONNECTTIMEOUT_MS, 5000);
		curl_setopt($this->_curl, CURLOPT_TIMEOUT_MS, 5000);
	}
	
	public function __destruct()
	{
		curl_close($this->_curl);
	}
	

	public function redisSet($key, $value)
	{
		$key = 'Wxplatform:' . $this->_wxplatform->id_wxplatform . ':' . $key;
		return app()->redis->set($key, $value);
	}
	
	public function redisSetex($key, $timeout, $value)
	{
		$key = 'Wxplatform:' . $this->_wxplatform->id_wxplatform . ':' . $key;
		return app()->redis->setex($key, $timeout, $value);
	}
	
	public function redisGet($key)
	{
		$key = 'Wxplatform:' . $this->_wxplatform->id_wxplatform . ':' . $key;
		return app()->redis->get($key);
	}
	
	public function switchPlatform($wxplatform = null)
	{
		if(empty($wxplatform)){
			$this->_wxplatform = Wxplatform::getDefaultPlatform();
		}elseif(is_numeric($wxplatform)){
			$this->_wxplatform = Wxplatform::model()->findByPk($wxplatform);
		}else{
			$this->_wxplatform = $wxplatform;
		}
	}
	
	public function getWxplatform()
	{
		return $this->_wxplatform;
	}
	
	public function init()
	{
		self::$_NOW = time();
		$this->_cInit();
		
		return parent::init();
	}
	
	protected function _runCurl($baseReq, $reqFields)
	{
		$url = empty($reqFields)? $baseReq : $baseReq . '?' . http_build_query($reqFields);
		curl_setopt($this->_curl, CURLOPT_URL, $url);
//		curl_setopt($this->_curl, CURLOPT_POSTFIELDS, $reqFields);
		$ret = curl_exec($this->_curl);
		
		return $ret;
	}
	
	protected function _runPostCurl($baseReq, $reqFields)
	{
		$url = $baseReq;
		curl_setopt($this->_curl, CURLOPT_URL, $url);
		curl_setopt($this->_curl, CURLOPT_POST, 1);
		curl_setopt($this->_curl, CURLOPT_POSTFIELDS, json_encode($reqFields, JSON_UNESCAPED_UNICODE));
		$ret = curl_exec($this->_curl);
		
		return $ret;
	}
	
	public function saveOauth2State($state)
	{
		$stateKey = 'OauthState:' . microtime(true) . '_' . rand(0, 999999);
		if(app()->redis->setex($stateKey, 120, json_encode($state))){
			return $stateKey;
		}else{
			return false;
		}
	}
	
	public function getOauth2State($stateKey)
	{
		$value = app()->redis->get($stateKey);
		return json_decode($value);
	}
	
	public function oAuthLogin($redirect_uri, $state, $response_type = 'code', $scope = 'snsapi_base')
	{
		//$scope = 'snsapi_base';
		//$scope = 'snsapi_userinfo';
		
		$redirect_uri = urlencode($redirect_uri);
		$state = $this->saveOauth2State($state);
		$authUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->_wxplatform->appid}&redirect_uri={$redirect_uri}&response_type={$response_type}&scope={$scope}&state={$state}#wechat_redirect";
		return app()->request->redirect($authUrl);
	}
	

	
	public function getUserInfo($access_token, $openid, $lang = 'zh_CN')
	{
		$retUserInfo = $this->_runCurl('https://api.weixin.qq.com/sns/userinfo', array(
			'access_token' => $access_token, 
			'openid' => $openid, 
			'lang' => $lang,
		));
		$retUserInfo = json_decode($retUserInfo);
		return $retUserInfo;
	}
	
	
	public function getMedia($media_id)
	{
		$ret = false;
		$cgiAccessToken = $this->getCgibinAccessToken('client_credential')->access_token;
		if(!isset($retAccessToken->errcode)){
			$i = 6;
			while($i--){
				sleep(1);
				
				$ret = $this->_runCurl('http://file.api.weixin.qq.com/cgi-bin/media/get', array(
					'access_token' => $cgiAccessToken,
					'media_id' => $media_id,
				));
				if($ret === false){		// net break
					continue;
				}
				$retDe = json_decode($ret);
				if(empty($retDe)){
					return $ret;
					break;
				}
			}
		}
		
		return false;
	}
	

	
	
	

	public function getOauth2AccessToken($code)
	{
	    $oauthAccessToken = $this->_runCurl('https://api.weixin.qq.com/sns/oauth2/access_token', array(
	        'appid' => $this->_wxplatform->appid,
	        'secret' => $this->_wxplatform->appsecret,
	        'code' => $code,
	        'grant_type' => 'authorization_code'
	    ));
	    return json_decode($oauthAccessToken);
	}
	
	const CGIBIN_ACCESS_TOKEN_KEY_CACHE = 'CGIBIN_ACCESS_TOKEN_KEY_CACHE';
	public function getCgibinAccessToken($refresh = false)
	{
	    $cachedKey = self::CGIBIN_ACCESS_TOKEN_KEY_CACHE . '.' . $this->_wxplatform->appid . '.' . $this->_wxplatform->appsecret;
	
	    if($refresh || empty( ($accessToken = $this->redisGet($cachedKey)) )){
	        $accessToken = $this->_runCurl('https://api.weixin.qq.com/cgi-bin/token', array(
	            'appid' => $this->_wxplatform->appid,
	            'secret' => $this->_wxplatform->appsecret,
	            'grant_type' => 'client_credential'
	        ));
	        
	        $accessTokenObj = json_decode($accessToken);
	        if(!empty($accessTokenObj->expires_in)){
    	        $cacheTime = empty($accessTokenObj->expires_in)? 300 : $accessTokenObj->expires_in;
    	        $this->redisSetex($cachedKey, $cacheTime, $accessToken);
	        }
	    }
	
	    return json_decode($accessToken);
	}
	
	public function getCardApiTicket($refresh = false)
	{
		$ret = $this->_runCurl(app()->params['FRONTEND_BASEURL'] . '/wxhelper/GetCardApiTicket', array(
			'appid' => $this->_wxplatform->appid,
			'appsecret' => $this->_wxplatform->appsecret,
		));
		$ret = json_decode($ret);
		
		return $ret;
	}
	
	public function getCgibinUserInfo( $openid, $lang = 'zh_CN')
	{
		$cgiAccessToken = $this->getCgibinAccessToken()->access_token;
		$ret = $this->_runCurl('https://api.weixin.qq.com/cgi-bin/user/info', array(
			'access_token' => $cgiAccessToken,
			'openid' => $openid,
			'lang' => $lang
		));
		$ret = json_decode($ret);
		return $ret;
	}
	
    const CGIBIN_TICKET_KEY_CACHE = 'CGIBIN_TICKET_KEY_CACHE';
	public function getCgibinTicket($refresh = false)
	{
	    $refresh = true;
		$cachedKey = self::CGIBIN_TICKET_KEY_CACHE . '.' . $this->_wxplatform->appid . '.' . $this->_wxplatform->appsecret;
		
		if($refresh || empty( ($ticket = $this->redisGet($cachedKey)) )){
			$cgiAccessToken = $this->getCgibinAccessToken()->access_token;
			$ticket = file_get_contents("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={$cgiAccessToken}&type=jsapi");
			$ticketObj = json_decode($ticket);
			
			$cacheTime = empty($accessTokenObj->expires_in)? 300 : $ticketObj->expires_in;
			$this->redisSetex($cachedKey, $cacheTime, $ticket);
		}
		
		return json_decode($ticket);
	}

	public function sendTemplateMessage($data)
	{
		$cgiAccessToken = $this->getCgibinAccessToken()->access_token;
	
		$oldCurlOptPost = curl_getinfo($this->_curl, CURLOPT_POST);
	
		curl_setopt($this->_curl, CURLOPT_POST, 1);
		curl_setopt($this->_curl, CURLOPT_POSTFIELDS, urldecode(urlencode(json_encode(($data)))));
		$ret = $this->_runCurl('https://api.weixin.qq.com/cgi-bin/message/template/send', array(
				'access_token' => $cgiAccessToken
		));
		$ret = json_decode($ret);
	
		curl_setopt($this->_curl, CURLOPT_POST, $oldCurlOptPost);
		return $ret;
	}


	public function checkSubscribed($openid)
	{
		$userInfoOnWx = $this->getCgibinUserInfo($openid);
	
		if(empty($userInfoOnWx->subscribe) || $userInfoOnWx->subscribe != 1){
			return false;
		}
	
		return true;
	}
		

	public $signature = '';
	public $wx_noncestr = '';
	public $wx_timestamp = '';
	public $wx_url = '';
	public function initWxJsConfig($jsApiList = array(), $render = true, $withScriptTag = false, $signType = 'sha1', $nonceStr = null, $timestamp = null)
	{
		$this->wx_noncestr = $nonceStr? $nonceStr : str_shuffle('abcdefghijklmnopqrstuvwxyz');
		$this->wx_timestamp = $timestamp? $timestamp : self::$_NOW;
		
		//$ticket = $this->getCgibinTicket(true)->ticket;
		$ticket = $this->getCgibinTicket()->ticket;
		
		$this->wx_url = app()->request->hostInfo . app()->request->getUrl();
		
		$str = "jsapi_ticket={$ticket}&noncestr={$this->wx_noncestr}&timestamp=".$this->wx_timestamp."&url={$this->wx_url}";
		
		if($signType == 'sha1'){
			$this->signature = sha1($str);
		}else{
			$this->signature = md5($str);
		}
		
		$initParam = array(
			'debug' => false,
			'appId' => $this->_wxplatform->appid,
			'timestamp' => $this->wx_timestamp,
			'nonceStr' => $this->wx_noncestr,
			'signature' => $this->signature,
			'jsApiList' => $jsApiList
		);
		
		$initStr = '
			wx.config('.
				json_encode($initParam)
			.');
		';
		if($withScriptTag){
			$initStr = '<script>'.$initStr.'</script>';
		}
		
		if($render){
			echo $initStr;
		}else{
			return $initStr;
		}
	}
	
	public function getUserRHashKey($id_wxuser)
	{
		return 'USER_RHASH_MERCHANT_PLATFORM_' . $id_wxuser;
	}
}